﻿using System;
using System.Text;

using NORM.Common;
using NORM.DataBase;
using NORM.Entity;

using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;

namespace NORM.SQLObject
{
    public partial class OQL
    {
        protected void ConditionsToParse(Condition[] inlist, out Condition[] outlist)
        {
            outlist = (Condition[])inlist.Clone();

            if (outlist != null)
            {
                for (int i = outlist.Length - 1; i >= 0; i--)
                {
                    int k = 1;
                    string str1 = outlist[i].Field;
                    for (int j = 0; j < outlist.Length; j++)
                    {
                        string str2 = outlist[j].Field;
                        if (i > j && str1.Equals(str2))
                        {
                            k++;
                        }
                    }

                    if (k > 1)
                        outlist[i].ParameterName = str1 + k.ToString();                     
                }

            }
        }

        protected void GetAsTableName(string tablename,out string tableasname)
        {
            int index = 1;            
            foreach (string s in modelnameArray)
            {
                if (string.Equals(s, tablename))
                {
                    break;
                }
                index++;
            }
            tableasname = "T" + index;
        }

        protected void ComparisonToParse(string comparison, out bool result)
        {
            result = true;
            if (!string.IsNullOrEmpty(comparison))
            {
                if (comparison.ToUpper().Contains("IN"))
                {
                    result = false;
                }
                else if (comparison.ToUpper().Contains("IS NOT"))
                {
                    result = false;
                }
                else if (comparison.ToUpper().Contains("IS"))
                {
                    result = false;
                }
            } 
        }

        protected void OrderBiesToParse(OQL oql)
        {
            if (oql._orderbies != null)
            {
                string _backsp = string.Empty;

                if (oql._parentoql != null)
                {
                    if (oql.sql.Contains("Limit"))
                    {
                        _backsp = oql.sql.Substring(oql.sql.LastIndexOf("Limit"));
                    }                     
                    if (!string.IsNullOrEmpty(_backsp))
                    {
                        _backsp = " " + _backsp.Replace(" ) ", "").TrimEnd(';');
                    }
                }

                foreach (object o in oql._orderbies)
                {
                    string by = o + "";
                    by = by.Replace("asc", "ASC").Replace("Asc", "ASC")
                        .Replace("desc", "DESC").Replace("Desc", "DESC");

                    string fieldname = string.Empty;
                    string ordertype = string.Empty;
                    if (by.Contains("ASC"))
                    {
                        fieldname = by.Substring(0, by.LastIndexOf("ASC")).Trim();
                        ordertype = "ASC";
                    }
                    else if (by.Contains("DESC"))
                    {
                        fieldname = by.Substring(0, by.LastIndexOf("DESC")).Trim();
                        ordertype = "DESC";
                    }
                    else
                    {
                        fieldname = by;
                        ordertype = "ASC";
                    }

                    if (this._join && fieldname.Contains("."))
                    {
                        string t = string.Empty;
                        string f = string.Empty;
                        f = fieldname.Substring(fieldname.LastIndexOf(".") + 1);
                        GetAsTableName(fieldname.Substring(0, fieldname.LastIndexOf(".")), out t);

                        if (oql._parentoql != null)
                            oql._parentoql.sql += "" + t + ".[" + f + "]" + " " + ordertype + " ,";
                        else
                            oql.sql += "" + t + ".[" + f + "]" + " " + ordertype + " ,";

                    }
                    else
                    {
                        if (oql._parentoql != null)
                            oql._parentoql.sql += "[" + fieldname + "]" + " " + ordertype + " ,";
                        else
                            oql.sql += "[" + fieldname + "]" + " " + ordertype + " ,";
                    }                   
                }

                if (oql._parentoql != null)
                    oql._parentoql.sql = oql._parentoql.sql.TrimEnd(',') + _backsp + ")" + " ORDER BY ";
                else
                    oql.sql = oql.sql.TrimEnd(',') + _backsp;
            }

        }

        protected void WhereToParse(OQL oql, int l, List<OsqlParameter> parameters)
        {
            string _resp = string.Empty;
            string _backsp = string.Empty;         
            string _childbacksp = string.Empty;
            string _childchildbacksp = string.Empty;

            if (l > 0)
            {
                _resp += "p_" + l + "_";

                if (oql.sql.Contains("ORDER BY") || oql.sql.Contains("GROUP BY"))
                    throw new Exception("子查询中不能含有ORDER BY/GROUP BY语句！");

                if (oql.sql.Contains("Limit"))
                {
                    _backsp = oql.sql.Substring(oql.sql.LastIndexOf("Limit"));
                }                              

                if (oql._childoql != null)
                {
                    WhereToParse(oql._childoql, l + 1, parameters);
                }                

                if (oql.sql.Contains("WHERE"))
                {                     
                    oql.sql = oql.sql.Substring(0, oql.sql.IndexOf("WHERE")) + " WHERE ";
                }
                if (!string.IsNullOrEmpty(_backsp))
                {
                    _backsp = " " + _backsp.Replace(" ) ", "").TrimEnd(';');
                }
            }

            int index = 0;

            Condition[] conditions;
            ConditionsToParse(oql._conditions, out conditions);

            foreach (Condition c in conditions)
            {
                if (!oql._join)
                {
                    if (!Type.Equals(c.Value.GetType(), typeof(OQL)))
                    {                       
                        string _nsql = string.Empty;

                        bool comparisonResult;
                        ComparisonToParse(c.Comparison, out comparisonResult);

                        if (comparisonResult)
                        {
                            OsqlParameter p = new OsqlParameter(_resp + c.ParameterName, c.Value);

                            if (index == 0)
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " [" + c.Field + "] " + c.Comparison + " @" + _resp + c.ParameterName;
                            }
                            else
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + c.Relation + " [" + c.Field + "] " + c.Comparison + " @" + _resp + c.ParameterName;
                            }

                            //if (this._commandcode != "300")
                            oql.sql += _nsql.ToString();

                            parameters.Add(p);

                        }
                        else
                        {
                            if (index == 0)
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " [" + c.Field + "] " + c.Comparison + " " + c.Value;
                            }
                            else
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + c.Relation + " [" + c.Field + "] " + c.Comparison + " " + c.Value;
                            }

                            //if (this._commandcode != "300")
                            oql.sql += _nsql.ToString();

                        }

                    }
                    else
                    {
                        string _nsql = string.Empty;

                        OQL suboql = (OQL)c.Value;
                        suboql._parentoql = oql;
                        oql._childoql = suboql;

                        WhereToParse(suboql, l + 1, parameters);

                        //OrderBiesToParse(suboql);

                        if (index == 0)
                        {
                            if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                _nsql = " [" + c.Field + "] " + c.Comparison + " ( " + suboql.ToString().TrimEnd(';') + " ) ";
                        }
                        else
                        {
                            if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                _nsql = " " + c.Relation + " [" + c.Field + "] " + c.Comparison + " ( " + suboql.ToString().TrimEnd(';') + " ) ";
                        }

                        //if (this._commandcode != "300")
                        oql.sql += _nsql.ToString();

                    }
                }
                else
                {

                    if (!Type.Equals(c.Value.GetType(), typeof(OQL)))
                    {
                        string t = string.Empty;
                        GetAsTableName(c.Field.Substring(0, c.Field.LastIndexOf(".")), out t);
                        string f = c.Field.Substring(c.Field.LastIndexOf(".") + 1);
                        string q = c.ParameterName.Substring(c.ParameterName.LastIndexOf(".") + 1);

                        string _nsql = string.Empty;

                        bool comparisonResult;
                        ComparisonToParse(c.Comparison, out comparisonResult);

                        if (comparisonResult)
                        {
                            OsqlParameter p = new OsqlParameter(t + "_" + q, c.Value);
                            if (index == 0)
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + t + "." + "[" + f + "] " + c.Comparison + " @" + t + "_" + q;
                            }
                            else
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + c.Relation + " " + t + "." + "[" + f + "] " + c.Comparison + " @" + t + "_" + q;
                            }

                            //if (this._commandcode != "300")
                            oql.sql += _nsql.ToString();

                            parameters.Add(p);

                        }
                        else
                        {
                            if (index == 0)
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + t + "." + "[" + f + "] " + c.Comparison + " " + c.Value;
                            }
                            else
                            {
                                if (this._commandcode != "UPDATE" || !ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                    _nsql = " " + c.Relation + " " + t + "." + "[" + f + "] " + c.Comparison + " " + c.Value;
                            }

                            //if (this._commandcode != "300")
                            oql.sql += _nsql.ToString();

                        }

                    }
                    else
                    {

                        string t = string.Empty;
                        GetAsTableName(c.Field.Substring(0, c.Field.LastIndexOf(".")), out t);
                        string f = c.Field.Substring(c.Field.LastIndexOf(".") + 1);

                        string _nsql = string.Empty;                       

                        OQL suboql = (OQL)c.Value;
                        suboql._parentoql = oql;
                        oql._childoql = suboql;

                        WhereToParse(suboql, l + 1, parameters);

                        //OrderBiesToParse(suboql);

                        if (index == 0)
                        {
                            if (this._commandcode != "UPDATE" || ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                _nsql = " " + t + "." + "[" + f + "]" + c.Comparison + " ( " + c.Value.ToString().TrimEnd(';') + " ) ";
                        }
                        else
                        {
                            if (this._commandcode != "UPDATE" || ArrayPlus.ContainsTableFieldKey(this._updatefields, c.Field))
                                _nsql = c.Relation + " " + t + "." + "[" + f + "] " + c.Comparison + " ( " + c.Value.ToString().TrimEnd(';') + " ) ";
                        }

                        //if (this._commandcode != "300")
                        oql.sql += _nsql.ToString();

                    }

                }

                index++;
            }

            oql.sql += _backsp;

        }

        protected void OrderByToParse(OQL oql)
        {
            if (oql._childoql != null)
                OrderBiesToParse(oql._childoql);
            OrderBiesToParse(oql);           
        }

        protected internal OQL JoinOnParse(string field1, string field2)
        {
            if (string.IsNullOrEmpty(field1) || string.IsNullOrEmpty(field2))
                throw new Exception(string.Format("{0} ON 附近有语法错误", this.sql + " ON " + field1 + "=" + field2));

            string t1 = string.Empty;
            GetAsTableName(field1.Substring(0, field1.LastIndexOf(".")), out t1);
            string t2 = string.Empty;
            GetAsTableName(field2.Substring(0, field2.LastIndexOf(".")), out t2);

            string f1 = field1.Substring(field1.LastIndexOf(".") + 1);
            string f2 = field2.Substring(field2.LastIndexOf(".") + 1);

            this.sql += " ON " + t1 + ".[" + f1 + "]=" + t2 + ".[" + f2 + "] ";

            return this;
        }
    }
}
